Heuristic to detect windows shutdown + power down domain.
authorshand@kneesaa.uk.xensource.com <shand@kneesaa.uk.xensource.com>
Wed, 16 Aug 2006 13:01:03 +0000 (14:01 +0100)
committershand@kneesaa.uk.xensource.com <shand@kneesaa.uk.xensource.com>
Wed, 16 Aug 2006 13:01:03 +0000 (14:01 +0100)
Signed-off-by: Steven Hand <steven@xensource.com>
Signed-off-by: George Dunlap <george.dunlap@xensource.com>
xen/arch/x86/hvm/svm/svm.c
xen/arch/x86/hvm/vmx/vmx.c

index 9f46235463c1d1abbca2e97a92087ad7055aab6f..e971f272e5e7ef1c76f59366f653a9070e7cf666 100644 (file)
@@ -2150,8 +2150,9 @@ done:
 static inline void svm_vmexit_do_hlt(struct vmcb_struct *vmcb)
 {
     struct vcpu *v = current;
-    struct periodic_time *pt=&v->domain->arch.hvm_domain.pl_time.periodic_tm;
-    s_time_t  next_pit = -1, next_wakeup;
+    struct periodic_time *pt = 
+        &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
+    s_time_t next_pit = -1, next_wakeup;
 
     __update_guest_eip(vmcb, 1);
 
@@ -2159,6 +2160,23 @@ static inline void svm_vmexit_do_hlt(struct vmcb_struct *vmcb)
     if ( vmcb->vintr.fields.irq || cpu_has_pending_irq(v) )
        return;
 
+    /* Detect machine shutdown.  Only do this for vcpu 0, to avoid
+       potentially shutting down the domain early. */
+    if (v->vcpu_id == 0) {
+        unsigned long rflags = vmcb->rflags; 
+        /* If we halt with interrupts disabled, that's a pretty sure
+           sign that we want to shut down.  In a real processor, NMIs
+           are the only way to break out of this.  Our SVM code won't
+           deliver interrupts, but will wake it up whenever one is
+           pending... */
+        if(!(rflags & X86_EFLAGS_IF)) {
+            printk("D%d: HLT with interrupts enabled @0x%lx  Shutting down.\n",
+                   current->domain->domain_id, (unsigned long)vmcb->rip);
+            domain_shutdown(current->domain, SHUTDOWN_poweroff);
+            return;
+        }
+    }
+
     if ( !v->vcpu_id )
         next_pit = get_scheduled(v, pt->irq, pt);
     next_wakeup = get_apictime_scheduled(v);
index ef84d539acdb62e3117d57eef82c2ec626962f60..ea52efdb33c46c67fd9d52e24484ef914d2fbeb7 100644 (file)
@@ -2054,9 +2054,32 @@ static inline void vmx_do_msr_write(struct cpu_user_regs *regs)
  */
 void vmx_vmexit_do_hlt(void)
 {
-    struct vcpu *v=current;
-    struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
-    s_time_t   next_pit=-1,next_wakeup;
+    struct vcpu *v = current;
+    struct periodic_time *pt = 
+        &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
+    s_time_t next_pit = -1, next_wakeup;
+
+
+    /* Detect machine shutdown.  Only do this for vcpu 0, to avoid
+       potentially shutting down the domain early. */
+    if (v->vcpu_id == 0) {
+        unsigned long rflags;
+        
+        __vmread(GUEST_RFLAGS, &rflags);
+        /* If we halt with interrupts disabled, that's a pretty sure
+           sign that we want to shut down.  In a real processor, NMIs
+           are the only way to break out of this.  Our VMX code won't
+           deliver interrupts, but will wake it up whenever one is
+           pending... */
+        if(!(rflags & X86_EFLAGS_IF)) {
+            unsigned long rip;
+            __vmread(GUEST_RIP, &rip);
+            printk("D%d: HLT with interrupts enabled @0x%lx  Shutting down.\n",
+                   current->domain->domain_id, rip);
+            domain_shutdown(current->domain, SHUTDOWN_poweroff);
+            return;
+        }
+    }
 
     if ( !v->vcpu_id )
         next_pit = get_scheduled(v, pt->irq, pt);